#include "ShadowHook.h"
#include "../SGD Wrappers/SGD_GraphicsManager.h"
#include "Game.h"
#include "GamePlayState.h"
#include "DestroyEntityMessage.h"
#include "Player.h"
#include "../SGD Wrappers/SGD_InputManager.h"
#include "../SGD Wrappers/SGD_Event.h"
#include "Enemy.h"
#include "Shadowmancer.h"
#include "../TinyXML/tinyxml.h"
#include "Physics.h"


Emitter ShadowHook::hook;
Emitter ShadowHook::anchorPoint;

ShadowHook::ShadowHook()
{
	image = SGD::GraphicsManager::GetInstance()->LoadTexture("resources/images/grapple.png");
	hook.NumParticles = 200;
	hook.SpawnRate = .001f;
	hook.Init();
	hook.owner = this;
	anchorPoint.NumParticles = 100;
	anchorPoint.SpawnRate = .001f;
	anchorPoint.Init();
	anchorPoint.owner = this;
}

ShadowHook::~ShadowHook()
{
	SGD::GraphicsManager::GetInstance()->UnloadTexture(image);

}

void ShadowHook::Render()
{
	/*SGD::GraphicsManager* graphics = SGD::GraphicsManager::GetInstance();
	graphics->DrawLine({ (GetOwner()->GetRect().ComputeCenter().x - Game::GetInstance()->GetCameraPos().x) * Game::GetInstance()->GetZoomLevel(),
		(GetOwner()->GetRect().ComputeCenter().y - Game::GetInstance()->GetCameraPos().y) * Game::GetInstance()->GetZoomLevel() },
		{ (this->GetRect().ComputeCenter().x - Game::GetInstance()->GetCameraPos().x) * Game::GetInstance()->GetZoomLevel(),
		(this->GetRect().ComputeCenter().y - Game::GetInstance()->GetCameraPos().y) * Game::GetInstance()->GetZoomLevel() },
		{ 255, 255, 255 }, 1);

	SGD::Point renderPos{ (position.x - Game::GetInstance()->GetCameraPos().x) * Game::GetInstance()->GetZoomLevel(),
		(position.y - Game::GetInstance()->GetCameraPos().y) * Game::GetInstance()->GetZoomLevel() };

	if (!attached)
	{
		SGD::GraphicsManager::GetInstance()->DrawTexture(image, renderPos, 0.0f, {}, {},
		{ Game::GetInstance()->GetZoomLevel(), Game::GetInstance()->GetZoomLevel() });
	}*/
	hook.Render();
	anchorPoint.Render();
}

void ShadowHook::Update(float elapsedTime)
{
	if (!attached)
	{
		Entity::Update(elapsedTime);
		hook.Position = anchorPoint.Position = GetRect().ComputeCenter();
	}
	//emitter update
	hook.ShadowUpdate(1, GetOwner(), elapsedTime);
	if (attached)
		anchorPoint.ShadowUpdate(0, GetOwner(), elapsedTime,&hook);

	SGD::Vector distance = GetOwner()->GetRect().ComputeCenter() - GetRect().ComputeCenter();
	float length = distance.ComputeLength();
	SGD::Vector normalized = distance.ComputeNormalized();

	if (GetOwner()->GetType() == Entity::ENT_PLAYER)
	{
		Player * player = dynamic_cast<Player *>(GetOwner());

		if (!player->GetGrappleActive())
		{
			DestroyEntityMessage* msg = new DestroyEntityMessage(this);
			msg->QueueMessage();
			msg = nullptr;
		}

		if (player->GetGrappledObject() != nullptr)
		{
			SetPosition(player->GetGrappledObject()->GetRect().ComputeCenter());
		}

		if (player->GetDestinationPlanet() != nullptr)
		{
			SGD::Vector distancetoplanet = player->GetDestinationPlanet()->GetRect().ComputeCenter() - GetRect().ComputeCenter();
			SGD::Vector distanceforplayer = player->GetRect().ComputeCenter() - player->GetDestinationPlanet()->GetRect().ComputeCenter();
			float angle = distancetoplanet.ComputeAngle(distanceforplayer);
			//length = distance.ComputeLength();
			//length -= 3.14159f * angle / 360 * player->GetDestinationPlanet()->GetRadius() * 2;
			//player->grappledistance = length;
			//moving hook point
			/*SGD::Vector toTarget = GetRect().ComputeCenter() - player->GetRect().ComputeCenter();
			SGD::Vector self = player->GetDestinationPlanet()->GetRect().ComputeCenter() - GetRect().ComputeCenter();
			self.Normalize();
			toTarget.Normalize();
			float dotprod = self.ComputeDotProduct(toTarget);
			if (fabs(dotprod) < 0.9f)
			{
				if (self.ComputeSteering(toTarget) < 0.0f)
					OrbitCounterClockwise(this, player->GetDestinationPlanet(),player->GetOrbitSpeed()/2+1);
				else
					OrbitClockwise(this, player->GetDestinationPlanet(),player->GetOrbitSpeed() / 2+1);
			}*/
			//Entity::Update(elapsedTime);
			//hook.Position = GetRect().ComputeCenter();
		}
		for (int iter = 0; iter < length && length < 400; iter++)
		{
			if (!attached)
			{
				chains[iter].active = true;
				chains[iter].position.x += -normalized.x * 15;
				chains[iter].position.y += -normalized.y * 15;
			}
		}

		if (length > 400 && player->GetDestinationPlanet() == nullptr)
		{
			DestroyEntityMessage* msg = new DestroyEntityMessage(this);
			player->SetGrappleActive(false);
			msg->QueueMessage();
			msg = nullptr;
		}
		if (length > 400 && player->GetDestinationPlanet() != nullptr && player->GetCurrentPlanet() != nullptr)
		{
			DestroyEntityMessage* msg = new DestroyEntityMessage(this);
			player->SetGrappleActive(false);
			player->SetDestinationPlanet(nullptr);
			msg->QueueMessage();
			msg = nullptr;
		}


		if (/*SGD::InputManager::GetInstance()->IsKeyPressed(SGD::Key::Space) || */ /*SGD::InputManager::GetInstance()->IsKeyPressed(SGD::Key::LButton) || */SGD::InputManager::GetInstance()->IsKeyPressed(SGD::Key::RButton))
		{
			DestroyEntityMessage* msg = new DestroyEntityMessage(this);
			msg->QueueMessage();
			msg = nullptr;
			player->SetGrappleActive(false);
			player->SetDestinationPlanet(nullptr);
			player->SetGrappledObject(nullptr);
		}

	}
	else
	{
		Shadowmancer*player = dynamic_cast<Shadowmancer*>(GetOwner());
		if (player->GetDestinationPlanet() != nullptr)

		{
			SGD::Vector distancetoplanet = player->GetDestinationPlanet()->GetRect().ComputeCenter() - GetRect().ComputeCenter();
			SGD::Vector distanceforplayer = player->GetRect().ComputeCenter() - player->GetDestinationPlanet()->GetRect().ComputeCenter();
			float angle = distancetoplanet.ComputeAngle(distanceforplayer);
			//length = distance.ComputeLength();
			//length -= 3.14159f * angle / 360 * player->GetDestinationPlanet()->GetRadius() * 2;
			player->grappledistance = length;
		}
		for (int iter = 0; iter < length && length < 400; iter++)
		{
			if (!attached)
			{
				chains[iter].active = true;
				chains[iter].position.x += -normalized.x * 15;
				chains[iter].position.y += -normalized.y * 15;
			}
		}

		if (length > 400 && player->GetDestinationPlanet() == nullptr)
		{
			DestroyEntityMessage* msg = new DestroyEntityMessage(this);
			player->attached = false;
			msg->QueueMessage();
			msg = nullptr;
		}
		if (!player->attached)
		{
			DestroyEntityMessage* msg = new DestroyEntityMessage(this);
			player->attached = false;
			player->SetDestinationPlanet(nullptr);
			msg->QueueMessage();
			msg = nullptr;
		}
	}

}

void ShadowHook::SetChains()
{
	for (int i = 0; i < 400; i++)
	{
		chains[i].position = position;
	}
}

void ShadowHook::HandleCollision(const IEntity* other)
{
	Player * player = dynamic_cast<Player*>(this->GetOwner());

	if (other->GetType() == ENT_PLANET)
	{

		if (!attached)
		{
			attached = true;
			const Planets* p = dynamic_cast<const Planets*>(other);
			Planets * planet = const_cast<Planets *>(p);
			if (GetOwner()->GetType() == Entity::ENT_PLAYER)
			{
				Player * player = dynamic_cast<Player*>(this->GetOwner());
				player->SetOrbitSpeed(0);
				player->SetDestinationPlanet(planet);
				player->SetCurrentPlanet(nullptr);

				SGD::Event e = { "SHADOWHOOK", &GetRect().ComputeCenter(), GetOwner() };
				e.SendEventNow(nullptr);
				if (player->GetGrappledObject() != nullptr)
				{
					const Entity* p = dynamic_cast<const Entity*>(other);
					Entity * object = const_cast<Entity *>(p);

					DestroyEntityMessage* msg = new DestroyEntityMessage(this);
					msg->QueueMessage();
					msg = nullptr;

					player->SetGrappleActive(false);
					player->SetDestinationPlanet(nullptr);
					player->SetGrappledObject(nullptr);


				}
			}
			else
			{
				Shadowmancer*mancer = dynamic_cast<Shadowmancer*>(GetOwner());
				mancer->SetDestinationPlanet(planet);
				SGD::Event e = { "SHADOWHOOK", &GetRect().ComputeCenter(), GetOwner() };
				e.SendEventNow(nullptr);
			}
		}

		
	}

	if (other->GetType() == ENT_BOSS)
	{
		if (!attached)
		{
			attached = true;
			const Planets* p = dynamic_cast<const Planets*>(other);
			Planets * planet = const_cast<Planets *>(p);
			if (GetOwner()->GetType() == Entity::ENT_PLAYER)
			{
				Player * player = dynamic_cast<Player*>(this->GetOwner());
				player->SetOrbitSpeed(0);
				player->SetDestinationPlanet(planet);
				player->SetCurrentPlanet(nullptr);

				SGD::Event e = { "SHADOWHOOK", &GetRect().ComputeCenter(), GetOwner() };
				e.SendEventNow(nullptr);
				if (player->GetGrappledObject() != nullptr)
				{
					const Entity* p = dynamic_cast<const Entity*>(other);
					Entity * object = const_cast<Entity *>(p);

					DestroyEntityMessage* msg = new DestroyEntityMessage(this);
					msg->QueueMessage();
					msg = nullptr;

					player->SetGrappleActive(false);
					player->SetDestinationPlanet(nullptr);
					player->SetGrappledObject(nullptr);


				}
			}
			else
			{
				Shadowmancer*mancer = dynamic_cast<Shadowmancer*>(GetOwner());
				mancer->SetDestinationPlanet(planet);
				SGD::Event e = { "SHADOWHOOK", &GetRect().ComputeCenter(), GetOwner() };
				e.SendEventNow(nullptr);
			}
		}
	}

	if (other->GetType() != ENT_PLANET && other->GetType() != ENT_BOSS && other->GetType() != ENT_PLAYER && other->GetType() != ENT_SHADOWMANCER &&other->GetType() != ENT_PROJECTILE && this->GetType() == ENT_GRAPPLE)
	{
		/*
		if (GetOwner()->GetType() == ENT_PLAYER)
		{
			if (!attached)
			{
				attached = true;
				const Entity* p = dynamic_cast<const Entity*>(other);
				Entity * object = const_cast<Entity *>(p);
				attachedObject = object;
				if (GetOwner()->GetType() == ENT_PLAYER)
				{
					Player * player = dynamic_cast<Player*>(this->GetOwner());
					player->SetGrappledObject(object);
				}
				if (object->GetType() == ENT_ENEMY)
				{
					Enemy * enemy = dynamic_cast<Enemy *>(object);
					enemy->SetCurrentPlanet(nullptr);
					enemy->SetState(State::standBy);
				}
				SGD::Vector pull = this->GetRect().ComputeCenter() - player->GetRect().ComputeCenter();
				pull.Normalize();
				object->SetVelocity(pull * -50);
				SGD::Event e = { "SHADOWHOOK", &GetRect().ComputeCenter(), GetOwner() };
				e.SendEventNow(nullptr);
			}
			else if (attached)
			{
				const Entity* p = dynamic_cast<const Entity*>(other);
				Entity * object = const_cast<Entity *>(p);
				if (object != player->GetGrappledObject())
				{
					DestroyEntityMessage* msg = new DestroyEntityMessage(this);
					msg->QueueMessage();
					msg = nullptr;
					player->SetGrappleActive(false);
					player->SetDestinationPlanet(nullptr);
					player->SetGrappledObject(nullptr);
				}
			}
		}
		*/
	}
	if (GetOwner()->GetType() == ENT_PLAYER)
	{
		/*
		if (other->GetType() != ENT_PLAYER && player->GetGrappledObject() != nullptr && player->GetGrappledObject() != other)
		{
			if (other->GetType() == ENT_ENEMY && player->GetGrappledObject()->GetType() == ENT_ENEMY)
			{

				const Entity* p = dynamic_cast<const Entity*>(other);
				Entity * object = const_cast<Entity *>(p);

				if (player->GetGrappledObject()->GetVelocity().ComputeLength() + object->GetVelocity().ComputeLength() > 500)
				{
					DestroyEntityMessage* msg = new DestroyEntityMessage(this);
					msg->QueueMessage();
					msg = nullptr;
					if (GetOwner()->GetType() == ENT_PLAYER)
					{
						Player * player = dynamic_cast<Player*>(this->GetOwner());
						player->SetGrappleActive(false);
						player->SetDestinationPlanet(nullptr);
						player->SetGrappledObject(nullptr);
					}
					else
					{
						Shadowmancer*sm = dynamic_cast<Shadowmancer*>(GetOwner());
						sm->SetDestinationPlanet(nullptr);
					}
				}
			}

			DestroyEntityMessage* msg = new DestroyEntityMessage(this);
			msg->QueueMessage();
			msg = nullptr;

			player->SetGrappleActive(false);
			player->SetDestinationPlanet(nullptr);
			player->SetGrappledObject(nullptr);

		}
		if (other->GetType() == ENT_PLAYER &&player->GetGrappledObject() != nullptr)
		{
			if (player->GetGrappledObject()->GetType() == ENT_ORB)
			{
				player->SetGrappleActive(false);
				player->SetDestinationPlanet(nullptr);
				player->SetGrappledObject(nullptr);

				DestroyEntityMessage* msgorb = new DestroyEntityMessage(player->GetGrappledObject());
				msgorb->QueueMessage();
				msgorb = nullptr;
				DestroyEntityMessage* msg = new DestroyEntityMessage(this);
				msg->QueueMessage();
				msg = nullptr;
			}
		}
		*/
	}


}